﻿//=====================================================================================================
// LocalizationLibrary
// The Localization Library is a collection of reusable software component that provide 
// support for localization. This library enable you to localize WPF, Silverlight and WP7 applications.
// (http://localizationlibrary.codeplex.com)
//=====================================================================================================
// Author: Nicola Gallo (Website: www.nicola.gallo.name, Email: nicolagmt@hotmail.it) 
//=====================================================================================================

namespace SLS.ExClassLib.Loc
{
    //.NET References
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;
    using System.Windows;
#if SILVERLIGHT && !WINDOWS_PHONE
    using System.Net;
    using System.Windows.Browser;
    using System.Windows.Resources;
    using System.Xml;
#endif

    /// <summary>
    /// Defines a base class to provide all application's assemblies.
    /// </summary>
    public class AssembliesProvider
    {
        //Properties

#if SILVERLIGHT && !WINDOWS_PHONE

        /// <summary>
        /// Gets the base uri.
        /// </summary>
        /// <returns></returns>
        private static Uri GetBaseUri()
        {
            Uri baseUri;
            String absoultePath = LocalizationManager.AppAbsolutePath;
            if (!String.IsNullOrEmpty(absoultePath))
            {
                baseUri = new Uri(absoultePath, UriKind.RelativeOrAbsolute);
            }
            else
            {
                absoultePath = System.IO.Path.GetFileName(HtmlPage.Document.DocumentUri.AbsolutePath);
                if (absoultePath.Length <= 0)
                {
                    absoultePath = HtmlPage.Document.DocumentUri.AbsoluteUri;
                    if (absoultePath.EndsWith("/"))
                    {
                        baseUri = new Uri(absoultePath, UriKind.RelativeOrAbsolute);
                    }
                    else
                    {
                        baseUri = new Uri(String.Format("{0}/", absoultePath), UriKind.RelativeOrAbsolute);
                    }
                }
                else
                {
                    baseUri = new Uri(HtmlPage.Document.DocumentUri.AbsoluteUri.Replace(absoultePath, String.Empty), UriKind.RelativeOrAbsolute);
                }
            }
            return baseUri;
        }

#endif

        //Methods

#if SILVERLIGHT && WINDOWS_PHONE

        /// <summary>
        /// Gets the assemblies that have been loaded into the current deployment.
        /// </summary>
        /// <returns>An array of assemblies in this application domain.</returns>
        public virtual Assembly[] GetCurrentDeploymentAssemblies()
        {
            List<Assembly> assemblies = new List<Assembly>();
            foreach (AssemblyPart assemblyPart in Deployment.Current.Parts)
            {
                String assemblyName = assemblyPart.Source.Replace(".dll", string.Empty);
                try
                {
                    Assembly assembly = Assembly.Load(assemblyName);
                    assemblies.Add(assembly);
                }
                catch (Exception ex)
                {
                    ConsoleExtended.WriteLine(String.Format("Exception when loading the assembly. MESSAGE: {0}", ex.Message));
                }
            }
            return assemblies.ToArray();
        }

#elif SILVERLIGHT

        /// <summary>
        /// Gets the assemblies that have been loaded into the current deployment.
        /// application domain.
        /// </summary>
        /// <returns>An array of assemblies in this application domain.</returns>
        public virtual Assembly[] GetCurrentDeploymentAssemblies()
        {
            List<Assembly> assemblies = new List<Assembly>();
            foreach (AssemblyPart assemblyPart in Deployment.Current.Parts)
            {
                Uri uri = new Uri(assemblyPart.Source, UriKind.Relative);
                StreamResourceInfo streamResourceInfo = Application.GetResourceStream(uri);
                try
                {
                    Assembly assembly = new AssemblyPart().Load(streamResourceInfo.Stream);
                    assemblies.Add(assembly);
                }
                catch (Exception ex)
                {

                    ConsoleExtended.WriteLine(String.Format("Exception when loading the AssemblyPart. MESSAGE: {0}", ex.Message));
                }
            }
            return assemblies.ToArray();
        }

        /// <summary>
        /// Loads the input <see cref="deploymentPart"/> deployment part.
        /// </summary>
        /// <param name="deploymentPart">Deployment part to load.</param>
        /// <param name="deploymentPartKind">Kind of deploymentpart.</param>
        public void LoadAssemblies(DeploymentPart deploymentPart, DeploymentPartKind deploymentPartKind)
        {
            switch (deploymentPartKind)
            {
                case DeploymentPartKind.Xap:
                    XapDeploymentPart xapDepolymentPart = deploymentPart as XapDeploymentPart;
                    if (xapDepolymentPart != null)
                    {
                        this.LoadXapDeploymentPart(xapDepolymentPart);
                    }
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// Loads the input <see cref="deploymentPart"/> deployment part.
        /// </summary>
        /// <param name="deploymentPart">Deployment part to load.</param>
        /// <returns>Loaded assemblies.</returns>
        private void LoadXapDeploymentPart(XapDeploymentPart deploymentPart)
        {
            if (deploymentPart != null)
            {
                String uriString = null;
                if (deploymentPart.Uri.IsAbsoluteUri)
                {
                    uriString = deploymentPart.Uri.AbsolutePath;
                }
                else 
                {
                    uriString = String.Format("{0}{1}", AssembliesProvider.GetBaseUri(), deploymentPart.Uri.OriginalString);
                }
                XapDeploymetPartAsyncResult xapDPAsyncResult = new XapDeploymetPartAsyncResult(null);
                Uri address = new Uri(uriString);
                WebClient webClient = new WebClient();
                webClient.OpenReadCompleted += (s, e) => 
                    {
                        if ((e.Error == null) && (e.Cancelled == false))
                        {
                            xapDPAsyncResult.CompletedSynchronously = true;
                            xapDPAsyncResult.IsCompleted = true;
                            xapDPAsyncResult.StreamResourceInfo = new StreamResourceInfo(e.Result, null);
                            Uri appManifestUri = new Uri("AppManifest.xaml", UriKind.Relative);
                            StreamResourceInfo appManifesSri = Application.GetResourceStream(xapDPAsyncResult.StreamResourceInfo, appManifestUri);
                            XmlReader reader = XmlReader.Create(appManifesSri.Stream);
                            if (reader.Read())
                            {
                                reader.ReadStartElement();
                                if (reader.ReadToNextSibling("Deployment.Parts"))
                                {
                                    while (reader.ReadToFollowing("AssemblyPart"))
                                    {
                                        xapDPAsyncResult.AssemblyParts.Add(new AssemblyPart() { Source = reader.GetAttribute("Source") });
                                    }
                                }
                            }
                        }
                        else 
                        {
                            xapDPAsyncResult.CompletedSynchronously = false;
                            xapDPAsyncResult.IsCompleted = false;
                        }
                        deploymentPart.Load(xapDPAsyncResult);
                    };
                webClient.OpenReadAsync(address);
            }
        }

#else

        /// <summary>
        /// Gets the assemblies that have been loaded into the execution context of the input <see cref="appDomain"/>
        /// application domain.
        /// </summary>
        /// <returns>An array of assemblies in this application domain.</returns>
        public virtual Assembly[] GetCurrentDomainAssemblies()
        {
            return AssemblyManager.GetAssemblies(AppDomain.CurrentDomain);
        }

        /// <summary>
        /// Gets the assemblies that have been loaded into the execution context of the input <see cref="appDomain"/>
        /// application domain.
        /// </summary>
        /// <param name="appDomain">Application domain.</param>
        /// <returns>An array of assemblies in this application domain.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown whether <paramref name="appDomain"/> parameter is null.
        /// </exception>
        public virtual Assembly[] GetAssemblies(AppDomain appDomain)
        {
            if (appDomain == null)
            {
                throw new ArgumentNullException("appDomain parameter shouldn't be null.");
            }
            return appDomain.GetAssemblies();
        }

#endif
    }
}